﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using Microsoft.Build.Framework;
using System.Threading;
using ModelViewerAux;
using Microsoft.Xna.Framework;

namespace ModelViewer
{

    public partial class BuildDlg : Form, ILogger
    {
        #region Delegates for thread communication
        
        public delegate void BuildComplete(bool success);
        public delegate void WarningMessage(string warning);
        public delegate void ErrorMessage(string error);

        #endregion

        /// <summary>
        /// The filename we are opening to build
        /// </summary>
        private string fileName;

        private ModelViewerControl control;
        private bool anyMessages = false;
        private bool success = false;

        #region Properties

        public ModelViewerControl ModelViewerControl { get { return control; } }
        public string FileName { get { return fileName; } }

        #endregion

        #region Construction and Initialization

        public BuildDlg()
        {
            this.control = null;
            InitializeComponent();
        }

        public BuildDlg(Form parent, string fileName, ModelViewerControl control)
        {
            // this.Parent = parent;
            this.fileName = fileName;
            this.control = control;
            InitializeComponent();

        }

        #endregion

        public void OnWarningMessage(string warning)
        {
            textWarnings.Text += warning + Environment.NewLine;
            textWarnings.SelectionStart = textWarnings.Text.Length;
            textWarnings.ScrollToCaret();
            textWarnings.Refresh();
            anyMessages = true;
        }

        public void OnErrorMessage(string error)
        {
            textErrors.Text += error + Environment.NewLine;
            textErrors.SelectionStart = textErrors.Text.Length;
            textErrors.ScrollToCaret();
            textErrors.Refresh();
            anyMessages = true;
        }

        public void OnBuildComplete(bool success)
        {
            this.success = success;
            if (success)
            {
                ContentManager contentManager = new ContentManager(ModelViewerControl.Services,
                                    builder.OutputDirectory);
                contentManager.Unload();

                // If the build succeeded, use the ContentManager to
                // load the temporary .xnb file that we just created.
                Model model = contentManager.Load<Model>("Model");

                string name = Path.GetFileName(fileName);
                ViewerModel vmodel = new ViewerModel(name, model);
                control.AddModel(vmodel);
            }


            Cursor = Cursors.Arrow;
            buttonOk.Enabled = true;


            if (!anyMessages)
            {
                if(success)
                {
                    this.DialogResult = System.Windows.Forms.DialogResult.OK;
                }
                else
                {
                    this.DialogResult = System.Windows.Forms.DialogResult.Abort;
                }

                this.Close();
            }
        }



        private void buttonOk_Click(object sender, EventArgs e)
        {
            if (success)
            {
                this.DialogResult = System.Windows.Forms.DialogResult.OK;
            }
            else
            {
                this.DialogResult = System.Windows.Forms.DialogResult.Abort;
            }

            this.Close();
        }

        private void OnLoad(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// The thread used to build the model. It builds in another thread 
        /// so it does not stall the interface.
        /// </summary>
        BuildThread builder = null;

        private void OnShown(object sender, EventArgs e)
        {
            buttonOk.Enabled = false;
            Cursor = Cursors.WaitCursor;

            // Create the active object
            builder = new BuildThread(this);
        }



        #region ILogger Members

        /// <summary>
        /// Initializes the custom logger, hooking the ErrorRaised notification event.
        /// </summary>
        public void Initialize(IEventSource eventSource)
        {
            if (eventSource != null)
            {
                eventSource.ErrorRaised += ErrorRaised;
                eventSource.WarningRaised += WarningRaised;
                eventSource.MessageRaised += MessageRaised;
            }
        }

        /// <summary>
        /// Shuts down the custom logger.
        /// </summary>
        public void Shutdown()
        {
        }

        /// <summary>
        /// Handles error notification events by storing the error message string.
        /// </summary>
        void ErrorRaised(object sender, BuildErrorEventArgs e)
        {
            Invoke(new ErrorMessage(OnErrorMessage), e.Message);
        }

        void WarningRaised(object sender, BuildWarningEventArgs e)
        {
            Invoke(new WarningMessage(OnWarningMessage), e.Message);
        }

        void MessageRaised(object sender, BuildMessageEventArgs e)
        {
            
        }

        /// <summary>
        /// Implement the ILogger.Parameters property.
        /// </summary>
        string ILogger.Parameters
        {
            get { return parameters; }
            set { parameters = value; }
        }

        string parameters = "";


        /// <summary>
        /// Implement the ILogger.Verbosity property.
        /// </summary>
        LoggerVerbosity ILogger.Verbosity
        {
            get { return verbosity; }
            set { verbosity = value; }
        }

        LoggerVerbosity verbosity = LoggerVerbosity.Normal;


        #endregion
    }

    #region The Build Thread Class

    public class BuildThread
    {
        BuildDlg buildDlg;
        ContentBuilder contentBuilder;
        private Thread thread;

        public string OutputDirectory { get; set; }


        public BuildThread(BuildDlg dlg)
        {
            this.buildDlg = dlg;

            // Start the thread
            thread = new Thread(new ThreadStart(Run));
            thread.Start();
        }

        /// <summary>
        /// Start thread execution
        /// </summary>
        public void Run()
        {
            // Create the content builder, passing us as the error logger
            contentBuilder = new ContentBuilder(buildDlg, buildDlg.ModelViewerControl.GraphicsDevice.GraphicsProfile);
            OutputDirectory = contentBuilder.OutputDirectory;

            // Tell the ContentBuilder what to build.
            contentBuilder.Add(buildDlg.FileName, "Model", null, "ModelViewerProcessor");

            // Build this new model data.
            bool buildSuccess = contentBuilder.Build();

            // Tell the foreground process we are done
            BuildDlg.BuildComplete buildComplete = new BuildDlg.BuildComplete(buildDlg.OnBuildComplete);
            buildDlg.Invoke(buildComplete, buildSuccess);
        }
    }

    #endregion
}
